import datetime
from package.fastapi.uuid7 import uuid7_hex
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy import Column, String, DateTime, Boolean, ForeignKey, UniqueConstraint, Text, BigInteger, Integer
from sqlalchemy.orm import relationship
from package.fastapi.crud import Crud


class Configure(Crud):
    """系统配置表"""
    __tablename__ = 'configure'
    name = Column(String, primary_key=True, comment='配置名')
    description = Column(String, default='', comment='配置描述')
    config = Column(JSONB, default={}, comment='配置详情')
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')


class Enum(Crud):
    """系统配置表"""
    __tablename__ = 'enum'
    name = Column(String, primary_key=True, comment='枚举名')
    description = Column(String, default='', comment='描述')
    option = Column(JSONB, default=[], comment='枚举项')
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')


class RoleUserRel(Crud):
    """角色用户多对多表关联"""
    __tablename__ = 'role_user'
    id = Column(String, primary_key=True, default=uuid7_hex, comment='主键ID')
    role_id = Column(String, ForeignKey("role.id", ondelete='CASCADE'), comment='角色ID')
    user_id = Column(String, ForeignKey("user.id", ondelete='CASCADE'), comment='用户ID')
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')


class Role(Crud):
    """角色表"""
    __tablename__ = 'role'
    id = Column(String, primary_key=True, default=uuid7_hex, comment='主键ID')
    name = Column(String, nullable=False, unique=True, comment='角色名')
    alias = Column(String, default='', comment='显示角色')
    description = Column(String, default='', comment='描述信息')
    permit = Column(JSONB, default=[], comment='功能权限信息')
    extra = Column(JSONB, default={}, comment='额外角色配置信息')
    inner = Column(Boolean, default=False, comment='是否内置')

    users = relationship('User', secondary='role_user', lazy='dynamic', backref='roles')
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')
    updated_at = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow,
                        comment='更新时间')


class Authorization(Crud):
    """用户授权码表"""
    __tablename__ = 'authorization'
    id = Column(String, primary_key=True, default=uuid7_hex, comment='主键ID')
    user_id = Column(String, ForeignKey("user.id", ondelete='CASCADE'), comment='用户ID')
    description = Column(String, comment='授权码描述')
    expired_at = Column(BigInteger, nullable=True, comment='过期日期 毫秒时间戳')
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')


class User(Crud):
    """用户表"""
    __tablename__ = 'user'
    KeyWord = ('name', 'alias')

    id = Column(String, primary_key=True, default=uuid7_hex, comment='主键ID')
    name = Column(String, unique=True, comment='账号')
    alias = Column(String, nullable=False, comment='显示别名')
    inner = Column(Boolean, default=False, comment='是否内置')

    password = Column(String, nullable=False, comment='密码')
    enabled = Column(Boolean, default=True, comment='是否启用')
    extra = Column(JSONB, default={}, comment='额外用户信息')

    authorization = relationship('Authorization', order_by=Authorization.created_at.desc, backref='user')
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')
    updated_at = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow, comment='更新时间')

    @property
    def role_ids(self):
        return [role.id for role in self.roles]

    @staticmethod
    def only_self(user):
        """仅自己"""
        return User.account == user['account']

    @staticmethod
    def same_dept(user):
        """同部门"""
        return User.extra.contains({'dept': user['extra'].get('dept')})


class NotifyConfigure(Crud):
    """通知配置"""
    __tablename__ = 'notify_configure'
    id = Column(String, primary_key=True, default=uuid7_hex, comment='主键ID')
    type = Column(String, nullable=False, comment='通告类型')
    name = Column(String, comment='通告名称')
    description = Column(String, default='', comment='描述')
    configure = Column(JSONB, default={}, comment='配置')

    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')
    updated_at = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow, comment='更新时间')

    __table_args__ = (UniqueConstraint('type', 'name'),)


class OIDCConfigure(Crud):
    """第三方登陆"""
    __tablename__ = 'oidc_configure'
    id = Column(String, primary_key=True, default=uuid7_hex, comment='主键ID')
    state = Column(String, unique=True, comment='OIDC名')
    client_id = Column(String, nullable=False, comment='客户端ID')
    client_secret = Column(String, default='', comment='密钥')
    authorization_url = Column(String, nullable=False, comment='认证地址')
    redirect_url = Column(String, default='', comment='回调地址')
    token_url = Column(String, default='', comment='token地址')
    verify_url = Column(String, default='', comment='verify地址')
    cert = Column(Text, default='', comment='证书')

    role = Column(String, default=None, comment='角色取值字段')
    userid_field = Column(String, default='', comment='用户ID取值字段')
    username_field = Column(String, default='', comment='用户名取值字段')
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')
    updated_at = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow, comment='更新时间')


class ApiKey(Crud):
    """系统apikey"""
    __tablename__ = 'apikey'
    id = Column(String, primary_key=True, default=uuid7_hex, comment='主键ID')
    name = Column(String, unique=True, comment='名称')
    description = Column(String, default='', comment='apikey描述')
    expired_at = Column(BigInteger, nullable=True, comment='过期日期 毫秒时间戳')
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')


#  数据分析模块
class SearchHistory(Crud):
    """搜索历史"""
    __tablename__ = 'search_history'

    id = Column(String, primary_key=True, default=uuid7_hex, comment='主键ID')
    search = Column(JSONB, comment='搜索条件')
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')


class SearchFavorite(Crud):
    """收藏搜索语句"""
    __tablename__ = 'search_favorite'
    id = Column(String, primary_key=True, default=uuid7_hex, comment='主键ID')
    user_id = Column(String, comment='用户ID')
    name = Column(String, comment='搜索名称')
    search = Column(JSONB, comment='搜索条件')
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')


class Panelib(Crud):
    """公共图表"""
    __tablename__ = 'panelib'
    id = Column(String, primary_key=True, default=uuid7_hex, comment='主键ID')
    name = Column(String, unique=True, comment='图表名')
    description = Column(String, nullable=False, comment='描述信息')
    type = Column(String, default='bar', comment='图片默认展示类型')

    search = Column(JSONB, default={}, comment='数据搜索配置 source | query')
    configure = Column(JSONB, default={}, comment='图表整体配置 分组字段 | 指标统计字段 | 别名映射')
    echart = Column(JSONB, default={}, comment='图表选项 {xaxis: [], yaxis: []} 风格|背景图|xxx')
    
    cron = Column(JSONB, default={'interval': 24, 'unit': 'hour'}, comment='定时任务执行配置')
    is_panelib = Column(Boolean, default=True, comment='是否panelib公共图表')
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')
    updated_at = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow, comment='更新时间')


class PanelibData(Crud):
    """公共图表 对应的缓存数据"""
    __tablename__ = 'panelib_data'
    id = Column(String, primary_key=True, default=uuid7_hex, comment='主键ID')
    cache = Column(JSONB, default=None, comment='图表缓存数据')
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')
    updated_at = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow, comment='更新时间')


class Dashboard(Crud):
    """仪表板配置"""
    __tablename__ = 'dashboard'
    id = Column(String, primary_key=True, default=uuid7_hex, comment='主键ID')

    name = Column(String, comment='仪表板名称')
    description = Column(String, default='', comment='描述信息')
    tags = Column(JSONB, default=[], comment='标签')
    configure = Column(JSONB, default={}, comment='仪表板配置 风格|背景|xx|刷新间隔')
    layout = Column(JSONB, default=[], comment='仪表板图表布局')
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')


class DashboardPanelibRelate(Crud):
    """仪表板 图表关联"""
    __tablename__ = 'dashboard_panelib_relate'
    id = Column(String, primary_key=True, default=uuid7_hex, comment='主键ID')
    dashboard_id = Column(String, ForeignKey("dashboard.id", ondelete='CASCADE'), comment='仪表板ID')
    panelib_id = Column(String, ForeignKey("panelib.id", ondelete='CASCADE'), comment='图表ID')
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')


class AlertConfigure(Crud):
    """告警配置"""
    __tablename__ = 'alert_configure'
    id = Column(String, primary_key=True, default=uuid7_hex, comment='主键ID')
    name = Column(String, comment='配置名称')
    description = Column(String, default='', comment='描述信息')
    category = Column(String, default='count', comment='告警类型')

    search = Column(JSONB, default={}, comment='仪表板配置 source|query|option')
    configure = Column(JSONB, default={}, comment='告警配置 分组|trigger|template|variables')
    cron = Column(JSONB, default={'interval': 24, 'unit': 'hour'}, comment='定时任务执行配置')
    suppress = Column(Integer, default=0, comment='通告抑制 min')
    notifies_configure = Column(JSONB, default=[], comment='告警通知')
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')


# 运维对象
class Devops(Crud):
    """运维对象"""
    __tablename__ = 'devops'
    id = Column(String, primary_key=True, default=uuid7_hex, comment='主键ID')
    name = Column(String, unique=True, comment='名称')
    category = Column(String, nullable=False, comment='运维对象类型')
    description = Column(String, nullable=False, comment='运维对象描述')

    host = Column(String, nullable=False, comment='IP/域名')
    port = Column(Integer, nullable=True, comment='端口')

    configure = Column(JSONB, default={}, comment='连接信息/认证信息')
    heartbeat_configure = Column(JSONB, default={}, comment='心跳检查配置')
    metricbeat_configure = Column(JSONB, default={}, comment='指标监控配置')
    extra = Column(JSONB, default={}, comment='额外运维信息 机房/机架/XXX')
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')
    updated_at = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow, comment='更新时间')


class Graph(Crud):
    """关系视图"""
    __tablename__ = 'graph'
    id = Column(String, primary_key=True, default=uuid7_hex, comment='主键ID')
    name = Column(String, unique=True, comment='名称')
    description = Column(String, nullable=False, comment='描述')
    configure = Column(JSONB, default={}, comment='视图配置 缩放比例/风格/背景/xxx')
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')
    updated_at = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow, comment='更新时间')


class StatisticDSM(Crud):
    """数据 源->模型 数据统计"""
    __tablename__ = 'statistic_dsm'
    id = Column(String, primary_key=True, comment='主键ID 索引名')
    is_writeable = Column(Boolean, default=True, comment='索引是否可写')

    firsted_at = Column(BigInteger, nullable=True, comment='最早接收')
    lasted_at = Column(BigInteger, nullable=True, comment='最近接收')
    count = Column(BigInteger, default=0, comment='模型数量')
    source = Column(JSONB, default={}, comment='模型下各个数据源的统计')
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')


class Agent(Crud):
    __tablename__ = 'agent'
    id = Column(String, primary_key=True, default=uuid7_hex, comment='主键ID')
    host = Column(String, comment='主机')
    os = Column(String, comment='系统')
    arch = Column(String, comment='架构')
    version = Column(String, comment='版本')
    status = Column(String, comment='状态')

    filebeat = Column(JSONB, default={}, comment='文件采集')
    winlogbeat = Column(JSONB, default={}, comment='win采集')
    metricbeat = Column(JSONB, default={}, comment='指标采集')
    packetbeat = Column(JSONB, default={}, comment='packet采集')
    heartbeat = Column(JSONB, default={}, comment='心跳采集')
    auditbeat = Column(JSONB, default={}, comment='audit采集')
    functionbeat = Column(JSONB, default={}, comment='func采集')
    journalbeat = Column(JSONB, default={}, comment='journal采集')

    processes = relationship('AgentProcess', backref='agent')
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')


class AgentProcess(Crud):
    __tablename__ = 'agent_process'
    id = Column(String, primary_key=True, default=uuid7_hex, comment='主键ID')
    agent_id = Column(String, ForeignKey("agent.id", ondelete='CASCADE'), comment='代理ID')
    name = Column(String, comment='进程名')
    command = Column(String, comment='系统')
    thread_count = Column(Integer, comment='线程数')
    pid = Column(Integer, comment='进程ID')
    ppid = Column(Integer, comment='父进程ID')
    username = Column(String, comment='用户名')
    status = Column(String, comment='状态')

    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')


class CollectorTask(Crud):
    """数据源采集方式任务"""
    __tablename__ = 'source_collector_task'
    id = Column(String, primary_key=True, default=uuid7_hex, comment='采集任务ID')
    source_id = Column(String, ForeignKey("source.id"), comment='数据源ID')
    category = Column(String, nullable=False, comment='数据源采集方式 api|database')
    name = Column(String, comment='采集任务名')
    description = Column(String, comment='采集任务描述')

    as_list = Column(Boolean, comment='采集数据拆分')
    configure = Column(JSONB, default={}, comment='采集配置')
    cron = Column(JSONB, default={'interval': 24, 'unit': 'hour'}, comment='定时任务执行配置')
    enabled = Column(Boolean, default=True, comment='开启/暂停')
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')
    updated_at = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow, comment='更新时间')


class Source(Crud):
    """数据源"""
    __tablename__ = 'source'
    id = Column(String, primary_key=True, default=uuid7_hex, comment='主键ID')
    category = Column(String, nullable=False, comment='数据源采集方式 api/database | syslog/udp/tcp/http/kafka')

    name = Column(String, unique=True, comment='数据源名称')
    description = Column(String, comment='数据源描述')
    host = Column(String, comment='IP/域名')
    port = Column(Integer, nullable=True, comment='端口')
    enabled = Column(Boolean, default=True, comment='开启/暂停')

    configure = Column(JSONB, default={}, comment='配置')
    interrupt_configure = Column(JSONB, default=None, comment='中断检查配置')
    parser_groups = relationship('ParserGroup', secondary='source_parsergroup_relate', lazy='dynamic', backref='sources')
    collectors = relationship('CollectorTask', order_by=CollectorTask.created_at.desc, backref='task')
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')
    updated_at = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow, comment='更新时间')


class ParserLib(Crud):
    """解析通用库"""
    __tablename__ = 'parser_lib'
    id = Column(String, primary_key=True, default=uuid7_hex, comment='主键ID')
    name = Column(String, comment='解析名称')
    inner = Column(Boolean, default=False, comment='内置')
    
    pipeline = Column(JSONB, default=None, comment='解析流程')
    
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')
    updated_at = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow, comment='更新时间')


class ParserMap(Crud):
    """解析字典"""
    __tablename__ = 'parser_map'
    id = Column(String, primary_key=True, default=uuid7_hex, comment='主键ID')
    name = Column(String, comment='解析字典名称')
    inner = Column(Boolean, default=False, comment='内置')
    configure = Column(JSONB, default={}, comment='映射表')
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')
    updated_at = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow, comment='更新时间')


class ParserRule(Crud):
    """解析规则"""
    __tablename__ = 'parser_rule'
    id = Column(String, primary_key=True, default=uuid7_hex, comment='主键ID')
    group_id = Column(String, ForeignKey('parser_group.id'), comment='分组ID')
    model_id = Column(String, ForeignKey('model.id'), comment='模型ID')
    name = Column(String, comment='解析名称')
    inner = Column(Boolean, default=False, comment='内置')
    
    sample = Column(Text, comment='样本')
    identifiers = Column(JSONB, default=[], comment='特征')
    extract = Column(JSONB, default={}, comment='画词解析')
    transforms = Column(JSONB, default=[], comment='数据转换')
    priority = Column(Integer, default=50, comment='优先级')
    
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')
    updated_at = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow, comment='更新时间')


class Model(Crud):
    """数据模型"""
    __tablename__ = 'model'
    id = Column(String, primary_key=True, default=uuid7_hex, comment='主键ID')
    name = Column(String, comment='模型名称')
    description = Column(String, comment='模型描述')
    inner = Column(Boolean, default=False, comment='内置')
    fields = Column(JSONB, default=[], comment='字段')
    policy = Column(JSONB, default=[], comment='模型策略')
    rules = relationship('ParserRule', backref='model')
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')

    @property
    def index(self):
        """索引名"""
        return f'dsm-{self.id}'
    
    @property
    def mappings(self): 
        """es字段表"""
        return {item['name']: {'type': item['type']} for item in self.fields}


class ParserGroup(Crud):
    __tablename__ = 'parser_group'
    id = Column(String, primary_key=True, default=uuid7_hex, comment='主键ID')
    name = Column(String, comment='解析规则组')
    description = Column(String, comment='描述信息')
    rules = relationship('ParserRule', order_by=ParserRule.priority.desc, backref='group')  # 优先级排序
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')


class SourceETLRelate(Crud):
    """数据解析工作流"""
    __tablename__ = 'source_parsergroup_relate'
    id = Column(String, primary_key=True, default=uuid7_hex, comment='主键ID')
    source_id = Column(String, ForeignKey("source.id", ondelete='CASCADE'), comment='数据源ID')
    parser_group_id = Column(String, ForeignKey("parser_group.id", ondelete='CASCADE'), comment='规则组ID')
    created_at = Column(DateTime, default=datetime.datetime.utcnow, comment='创建时间')
